/** file FilterConvolution.cpp
    author belot.nicolas

*/

#include "FilterConvolution.h"
#include <iostream>
#include <sys/time.h>
namespace libtrckr {
string FilterConvolution::HowToTune(){
	return "MultiBand X -100 +100";
}
FilterConvolution::FilterConvolution():Convolution(){
	convolutionW = 0;
	Wsize=0;
}

FilterConvolution::FilterConvolution(int size):Convolution(size){
	convolutionW = 0;
	Wsize=0;
}

FilterConvolution::FilterConvolution(double* data, int size):Convolution(data,size){
	convolutionW = 0;
	Wsize=0;
}

FilterConvolution::FilterConvolution(const Buffer& b):Convolution(b){
	convolutionW = 0;
	Wsize=0;
}

FilterConvolution::FilterConvolution(const FilterConvolution& f):Convolution(f){
	convolutionW = 0;
	Wsize=0;
}

FilterConvolution::~FilterConvolution(){
	if(convolutionW!=0)
		free(convolutionW);
}


void FilterConvolution::Init(){
	if(convolutionW!=0)
		free(convolutionW);
}

void FilterConvolution::Tune(DynArray<int> conf){
	double *data=(double*)malloc(sizeof(double)*conf.size());
	for(uint i=0;i<conf.size();i++){
		data[i]=(0. + conf[i])/100.0;
	}
	setContent(data,conf.size());
// 	std::cout << conf.size() << std::endl;
	free(data);
}

Buffer& FilterConvolution::Preview(Buffer& b){
	if(convolutionW==0){
		convolutionW=(double*)malloc(sizeof(double)*(b.size()+getSize()));
		Wsize=b.size()+getSize();
		// set all bytes to 0
		memset(convolutionW,0,sizeof(double)*Wsize);
		//for(uint i=0;i< Wsize;i++) convolutionW[i]=.0;
		start=0;end=Wsize;
	}else if(Wsize < b.size() + getSize()){
		//We need to reallocate a Buffer an copy the data in :(
		//Maybe should use realloc ?
		//as we allocate a new buffer and copy data into it and free the dol one...
		double *tmp=(double*)realloc(convolutionW, sizeof(double)*b.size()+getSize());
		if(tmp==0){
			//trouble!!!
			return b;
		}
		//double *tmp=(double*)malloc(sizeof(double)*(b.size()+getSize()));
		//copy old data
		//memcpy(tmp, convolutionW+start, sizeof(double)*getSize());
		//set to 0 the rest
		
		//data beetween tmp +wsize and b.size()+getSize() are uninitialized
		memset(tmp+Wsize, 0, sizeof(double)*(getSize()+b.size()-Wsize));
		/*for(uint i=Wsize;i< getSize()+b.size();i++){
			tmp[i]=.0;
		}*/
		Wsize=getSize()+b.size();
		//liberated old data ..
		//free(convolutionW);
		convolutionW=tmp;
		start=0;end=Wsize;
	}
	//Convolution itself
	int element=0;
	double *convolutionD = getCoef();
	
	for(uint j=0;j<getSize();j++){
		if(convolutionD[j]==0) continue;

		for(uint i=0;i<b.size();i++){
			if(b[i]==0) continue;
			element=start+i+j;
				if(element>=Wsize)
					element-=Wsize;	
				convolutionW[element]+=b[i]*convolutionD[j];
		}
	}
	//Fill Buffer with new Data
	if(start+b.size() < Wsize){
		//memcpy(b.getContent(),convolutionW+start, sizeof(double)*b.size());
		//memset(convolutionW+start,0, sizeof(double)*b.size());
		for(uint i=0;i<b.size();i++){
			b[i]=convolutionW[start+i];
			convolutionW[start+i]=0.;
		}
		/*for(uint i=0;i<b.size();i++)
			convolutionW[start+i]=0.0;*/
	}else{
	//Rearrrage Data in convolutionW;
		//int si= Wsize-start;
		int element;
		for(uint i=0;i<b.size();i++){
			element=start+i;
			if(element >= Wsize){
				element-=Wsize;
			}
			b[i]=convolutionW[element];
			convolutionW[element]=0.;
		}

		
		//memcpy(b.getContent(), convolutionW+start,sizeof(double)*si);
		//memset(convolutionW+start,0, sizeof(double)*si);
		/*for(uint i=0;i<si;i++){
			convolutionW[start+i]=.0;
		}*/
		//memcpy(b.getContent()+si, convolutionW, sizeof(double)*(b.size()-si));
		//memset(convolutionW, 0, sizeof(double) *(b.size()-si));
		/*for(uint i=0;i< b.size()-si;i++){
			convolutionW[i]=.0;
		}*/
	}
	start=start+b.size();
	if(start > Wsize) start-=Wsize;	
	return b;
}

double* FilterConvolution::Preview(double* data, int size){
	if(convolutionW==0){
		convolutionW=(double*)malloc(sizeof(double)*(size+getSize()));
		Wsize=size+getSize();
		for(uint i=0;i< Wsize;i++) convolutionW[i]=.0;
		start=0;end=Wsize;
	}else if(Wsize < size + getSize()){
		//We need to reallocate a Buffer an copy the data in :(
		//Maybe should use realloc ?
		//as we allocate a new buffer and copy data into it and free the dol one...
		double *tmp=(double*)realloc(convolutionW, sizeof(double)*size+getSize());
		if(tmp==0){
			//trouble!!!
			return data;
		}
		//double *tmp=(double*)malloc(sizeof(double)*(b.size()+getSize()));
		//copy old data
		//memcpy(tmp, convolutionW+start, sizeof(double)*getSize());
		//set to 0 the rest
		
		//data beetween tmp +wsize and b.size()+getSize() are uninitialized
		for(uint i=Wsize;i< getSize()+size;i++){
			tmp[i]=.0;
		}
		Wsize=getSize()+size;
		//liberated old data ..done by realloc
		//free(convolutionW);
		convolutionW=tmp;
		start=0;end=Wsize;
	}
	//Convolution itself
	int element=0;
	double *convolutionD = getCoef();
	for(uint i=0;i<size;i++){
		for(uint j=0;j<getSize();j++){
				if(convolutionD[j]!=0 && data[i]!=0){
					element=start+i+j;
					if(element>Wsize)
						element-=Wsize;	
					convolutionW[element]+=data[i]*convolutionD[j];
				}
		}
	}
	
	//Fill Buffer with new Data
	if(start+size < Wsize){
		memcpy(data,convolutionW+start, sizeof(double)*size);
		for(uint i=0;i<size;i++)
			convolutionW[start+i]=0.0;
	}else{
	//Rearrrage Data in convolutionW;
		int si= size-start;
		memcpy(data, convolutionW+start,sizeof(double)*si);
		for(uint i=0;i<si;i++){
			convolutionW[start+i]=.0;
		}
		memcpy(data+si, convolutionW, sizeof(double)*(size-si));
		for(uint i=0;i< size-si;i++){
			convolutionW[i]=.0;
		}
	}
	start=start+size;	
	return data;
}


Buffer& FilterConvolution::Execution(Buffer & b){
	return Preview(b);
}

double* FilterConvolution::Execution(double* data, int size){
	return Preview(data,size);
}

}

